#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include "request.h"
#include "monitor.h"
using namespace std;

#define STARTING_TRACK 4
//the average seek time for a desktop disk is typically around 9000 microseconds
#define DISK_MOVEMENT_OVERHEAD 3000
#define DATA_ACCESS_OVERHEAD 10

#define RUNTIME 5

// create struct to pass threadid and
typedef struct threadInput {
   int tid;
   monitor* mon;
}  threadInput;

void *worker(void *ptr)
{
	threadInput *data = (threadInput*)ptr;
	
	int new_track, work_size, work_overhead, disk_head_movement;
	int previous_track = STARTING_TRACK;

	time_t start_time;
	double run_time = RUNTIME;
	
	start_time = time(NULL);

	while(difftime(time(NULL), start_time) < run_time){
		//if the monitor's output queue is empty, put thread to sleep
		cout << difftime(time(NULL), start_time) << endl;
		
		request* currentReq = data->mon->removeRequest();
		//request* currentReq = new request(0, 1);
		
		// TODO: HANDLE NULL REQUEST OBJECTS
				
		//retrieves the relevant request data
		new_track = currentReq->getTrackNum();
		work_size = currentReq->getWorkSize();
		
		//calculates the distance the disk head has to travel to service the request
		disk_head_movement = abs(new_track - previous_track);

		//calculates a length of time "required" to access the requested data from the disk
		work_overhead = (DISK_MOVEMENT_OVERHEAD * disk_head_movement) + (DATA_ACCESS_OVERHEAD * work_size);

		//freezes the thread to simulate the I/O request
		usleep(work_overhead);

		//sends results of the service back to the client
		//(to be updated when we decide what we want to give to the client)
		//currentReq->setOutputData( (char) work_overhead);
		currentReq->setWorkFinished(true);
		
		cout << "The work has been finished in " << work_overhead << " ms." << endl;

		//updates the location of the disk head
		previous_track = new_track;
		
		//} end the processing loop
		
		//else{pthread_yield;}
		

	}
	cout << "Loop has finished" << endl;
	
	pthread_exit(NULL);
}

int main(int argc, char **argv) {
    pthread_t thr;
	monitor* smon = new monitor();

    cout << "Creating thread..." << endl;

	threadInput worker_data;
	worker_data.tid = 1;
	worker_data.mon = smon;
    pthread_create(&thr, NULL, worker, (void*)&worker_data);
    
    pthread_join(thr, NULL);

};
